package top.yxqz.spring.aop.annotation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author: 余小小
 * @date: 2023/4/14
 * @description：日志切面类
 * @Aspect：切面，用了它，spring就会把它认为是一个切面 通知的种类：
 * 1. 前置通知：在被代理的目标方法前执行 @Before()
 * 2. 返回通知：在被代理的目标方法成功结束后执行（寿终正寝） @AfterReturning
 * 3. 异常通知：在被代理的目标方法异常结束后执行（死于非命）@AfterThrowing
 * 4. 后置通知：在被代理的目标方法最终结束后执行（盖棺定论）  @After
 * 5. 环绕通知：使用try...catch...finally结构围绕整个被代理的目标方法，包括上面四种通知对应的所 有位置
 * 所有通知，都必须要要有切入点作为参数
 */
@Component
@Aspect
public class CalculatorLoggerAspect {

    /**
     * 切入点表达式
     * 1.常规用法：  execution（修饰符 方法的返回值 方法的所在的类的全类名路径.方法名（参数类型，参数类型，xxxxx））
     * execution(public  void top.yxqz.spring.aop.annotation.CalculatorImpl.add(int,int))
     * 2.通配符的写法：execution（* 方法的所在的类的全类名路径.*（..）)
     * 3.使用自定义的切点方法
     */
    @Pointcut("execution(* top.yxqz.spring.aop.annotation.CalculatorImpl.*(..))")
    public void myPointcut() {
    }


    /**
     * 前置通知
     */
//    @Before("execution(public int top.yxqz.spring.aop.annotation.CalculatorImpl.add(int,int))")
    @Before("myPointcut()")
    public void beforeAdviceMethod() {
        System.out.println("1.前置通知——beforeAdviceMethod");
    }

    /**
     * 后置通知
     */
    @After("myPointcut()")
    public void afterAdviceMethod() {
        System.out.println("2.后置通知——afterAdviceMethod");
    }

    /**
     * 返回通知:在后置通知之前，执行目标方法得到返回值
     * 返回值：目标方法的返回值
     * returning属性：拿到的返回值
     * 1.属性值是我们在通知方法参数的参数名
     * 2.方法的参数类型，必须是目标方法的返回值类型
     * value属性：切入点
     */
    @AfterReturning(value = "myPointcut()", returning = "returnValue")
    public void afterReturningAdviceMethod(int returnValue) {
        System.out.println("3.返回通知——afterReturningAdviceMethod");
        System.out.println("目标方法的返回值是：" + returnValue);
    }

    /**
     * 异常通知:目标方法异常才会触发
     * value属性：切入点
     * throwing属性：拿到的异常对象
     * 1.属性值是我们在通知方法参数的参数名
     * 2.方法的参数类型，必须是异常类型
     * spring会自动将通知中的参数类型，创建相关对象，如果想要一个对象（由Spring来帮我们创建），可以使用参数的方式
     */
    @AfterThrowing(value = "myPointcut()", throwing = "exception")
    public void afterThrowingAdviceMethod(Exception exception) {
        System.out.println("4.异常通知——afterThrowingAdviceMethod");
        System.out.println("异常信息是：" + exception.getMessage());
    }

    /**
     * 环绕通知:包含了上面的所用通知
     * 使用逻辑的形式，可以实现上面的4种通知
     */
    @Around("myPointcut()")
    public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("5.环绕通知——aroundAdviceMethod");
        return null;
    }
}
